{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "51a4c8f9-e041-4f9a-8da0-f4ad97c8eb46",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iteration: 0, Loss: 27.071214829194115\n",
      "Iteration: 100, Loss: 33.78905859777454\n",
      "Iteration: 200, Loss: 19.9137512981971\n",
      "Iteration: 300, Loss: 13.531068193689691\n",
      "Iteration: 400, Loss: 10.64546615844617\n",
      "Iteration: 500, Loss: 9.277353455475065\n",
      "Iteration: 600, Loss: 8.5180420459565\n",
      "Iteration: 700, Loss: 8.014061987588422\n",
      "Iteration: 800, Loss: 7.636756824775691\n",
      "Iteration: 900, Loss: 7.3365637403711235\n",
      "Training completed.\n",
      "['id_0', 5.1749603989847355]\n",
      "['id_1', 18.30621425352791]\n",
      "['id_2', 20.49121809418055]\n",
      "['id_3', 11.523942869805389]\n",
      "['id_4', 26.61605675230612]\n",
      "['id_5', 20.53134808176123]\n",
      "['id_6', 21.906551018797373]\n",
      "['id_7', 31.736468747068823]\n",
      "['id_8', 13.391674055111723]\n",
      "['id_9', 64.45646650291953]\n",
      "['id_10', 20.26456883615945]\n",
      "['id_11', 15.358576077361223]\n",
      "['id_12', 68.58947276926725]\n",
      "['id_13', 48.42811374745718]\n",
      "['id_14', 18.70233382419319]\n",
      "['id_15', 10.188595737466702]\n",
      "['id_16', 30.740362859820447]\n",
      "['id_17', 71.1322177635511]\n",
      "['id_18', -4.130517391262453]\n",
      "['id_19', 18.235694016428685]\n",
      "['id_20', 38.57892227500776]\n",
      "['id_21', 71.3115197253133]\n",
      "['id_22', 7.410348162634087]\n",
      "['id_23', 18.717955330321402]\n",
      "['id_24', 14.937250260084584]\n",
      "['id_25', 36.719736694705325]\n",
      "['id_26', 17.961697005662682]\n",
      "['id_27', 75.78946287210539]\n",
      "['id_28', 12.309310248614459]\n",
      "['id_29', 56.29535173964956]\n",
      "['id_30', 25.113160865661484]\n",
      "['id_31', 4.610248674094046]\n",
      "['id_32', 2.4837705545150093]\n",
      "['id_33', 24.759422261321266]\n",
      "['id_34', 30.480280465591154]\n",
      "['id_35', 38.46393074642664]\n",
      "['id_36', 44.20231060933006]\n",
      "['id_37', 30.086836019866]\n",
      "['id_38', 40.47367501574009]\n",
      "['id_39', 29.226479902317386]\n",
      "['id_40', 5.60645605434392]\n",
      "['id_41', 38.66601607878962]\n",
      "['id_42', 34.6102134318772]\n",
      "['id_43', 48.389697507384795]\n",
      "['id_44', 14.757247666944133]\n",
      "['id_45', 34.46682011087208]\n",
      "['id_46', 27.48310687418434]\n",
      "['id_47', 12.000879378154062]\n",
      "['id_48', 21.378036151603784]\n",
      "['id_49', 28.544403091663288]\n",
      "['id_50', 20.1655138184116]\n",
      "['id_51', 10.796678149746485]\n",
      "['id_52', 22.171035755750147]\n",
      "['id_53', 53.446263109352266]\n",
      "['id_54', 12.219581121610016]\n",
      "['id_55', 43.30096845517155]\n",
      "['id_56', 32.18233510328541]\n",
      "['id_57', 22.567217514570785]\n",
      "['id_58', 56.73951416554706]\n",
      "['id_59', 20.745052945295466]\n",
      "['id_60', 15.028854557473288]\n",
      "['id_61', 39.85530159038513]\n",
      "['id_62', 12.975340680728298]\n",
      "['id_63', 51.74165959283004]\n",
      "['id_64', 18.78336963253988]\n",
      "['id_65', 12.348752842777712]\n",
      "['id_66', 15.633623653541923]\n",
      "['id_67', -0.05887147068502552]\n",
      "['id_68', 41.50801107307593]\n",
      "['id_69', 31.548747530656]\n",
      "['id_70', 18.60425115754707]\n",
      "['id_71', 37.47681972488066]\n",
      "['id_72', 56.52039065762305]\n",
      "['id_73', 6.587877193521952]\n",
      "['id_74', 12.229339737435017]\n",
      "['id_75', 5.203696404134643]\n",
      "['id_76', 47.92737510380061]\n",
      "['id_77', 13.020705685594645]\n",
      "['id_78', 17.11030169390361]\n",
      "['id_79', 20.603234531002048]\n",
      "['id_80', 21.284481560784595]\n",
      "['id_81', 38.69293529051179]\n",
      "['id_82', 30.020716675725836]\n",
      "['id_83', 88.76740666723548]\n",
      "['id_84', 35.98470023966825]\n",
      "['id_85', 26.756913553477187]\n",
      "['id_86', 23.96351684356436]\n",
      "['id_87', 32.747242828083074]\n",
      "['id_88', 22.189043755319894]\n",
      "['id_89', 20.99215885362657]\n",
      "['id_90', 29.555994316645435]\n",
      "['id_91', 40.992168866517794]\n",
      "['id_92', 8.625117809911552]\n",
      "['id_93', 32.3214718088779]\n",
      "['id_94', 46.59804436536758]\n",
      "['id_95', 22.88407082672354]\n",
      "['id_96', 31.51812972825165]\n",
      "['id_97', 11.19823347976609]\n",
      "['id_98', 28.527436642529597]\n",
      "['id_99', 0.29115068008963024]\n",
      "['id_100', 17.966961079539715]\n",
      "['id_101', 27.124163929470143]\n",
      "['id_102', 11.398232780652826]\n",
      "['id_103', 16.426426865673506]\n",
      "['id_104', 23.4252610469222]\n",
      "['id_105', 40.6160826705684]\n",
      "['id_106', 25.86412502656036]\n",
      "['id_107', 5.422736951672397]\n",
      "['id_108', 10.794921122256111]\n",
      "['id_109', 72.86213692992128]\n",
      "['id_110', 48.02283705948137]\n",
      "['id_111', 15.746808276902994]\n",
      "['id_112', 24.67041061417793]\n",
      "['id_113', 12.827793326536716]\n",
      "['id_114', 10.158057570240492]\n",
      "['id_115', 27.269223342020993]\n",
      "['id_116', 29.20873857793241]\n",
      "['id_117', 8.835339619930757]\n",
      "['id_118', 20.051088137129724]\n",
      "['id_119', 20.212333743764262]\n",
      "['id_120', 79.90600929870558]\n",
      "['id_121', 18.0616142882636]\n",
      "['id_122', 30.5428093413043]\n",
      "['id_123', 25.980792377728026]\n",
      "['id_124', 5.212577268164761]\n",
      "['id_125', 30.355697305856193]\n",
      "['id_126', 7.768322888914632]\n",
      "['id_127', 15.328268255393306]\n",
      "['id_128', 22.666365717697968]\n",
      "['id_129', 62.742054211090085]\n",
      "['id_130', 18.950780367988006]\n",
      "['id_131', 19.07635563083853]\n",
      "['id_132', 61.371574091637115]\n",
      "['id_133', 15.88456205262971]\n",
      "['id_134', 13.409418077705547]\n",
      "['id_135', 0.8487724836112802]\n",
      "['id_136', 7.8349967173041275]\n",
      "['id_137', 57.01282901179679]\n",
      "['id_138', 25.607996751813815]\n",
      "['id_139', 4.961704729242069]\n",
      "['id_140', 36.41487903906274]\n",
      "['id_141', 28.790006721975978]\n",
      "['id_142', 49.19412096197633]\n",
      "['id_143', 40.306869855734455]\n",
      "['id_144', 13.316180593982674]\n",
      "['id_145', 27.661011875229146]\n",
      "['id_146', 17.15802752436675]\n",
      "['id_147', 49.68726256929677]\n",
      "['id_148', 23.030272291604764]\n",
      "['id_149', 39.24093652484275]\n",
      "['id_150', 13.196753889412562]\n",
      "['id_151', 5.948893701039439]\n",
      "['id_152', 25.82160897630424]\n",
      "['id_153', 8.258634214291625]\n",
      "['id_154', 19.146320517225583]\n",
      "['id_155', 43.18248652651673]\n",
      "['id_156', 6.717843578093046]\n",
      "['id_157', 33.86961524681066]\n",
      "['id_158', 15.369937846981802]\n",
      "['id_159', 16.939044973551923]\n",
      "['id_160', 37.885336794634824]\n",
      "['id_161', 19.202484541054414]\n",
      "['id_162', 9.059504715654734]\n",
      "['id_163', 10.283399610648473]\n",
      "['id_164', 48.672447125698284]\n",
      "['id_165', 30.58771621323084]\n",
      "['id_166', 2.4774098975321817]\n",
      "['id_167', 12.81160393780592]\n",
      "['id_168', 70.32478980976464]\n",
      "['id_169', 14.840967694067038]\n",
      "['id_170', 68.86558756678863]\n",
      "['id_171', 42.74199244486631]\n",
      "['id_172', 24.00026154292019]\n",
      "['id_173', 23.420724860321435]\n",
      "['id_174', 61.67212443568236]\n",
      "['id_175', 25.494202845059206]\n",
      "['id_176', 19.004809786869068]\n",
      "['id_177', 34.88668288189684]\n",
      "['id_178', 9.402313398379691]\n",
      "['id_179', 29.520011314408016]\n",
      "['id_180', 14.573965885700467]\n",
      "['id_181', 9.12556314320357]\n",
      "['id_182', 52.812583998131885]\n",
      "['id_183', 45.03953799438958]\n",
      "['id_184', 17.452434679183288]\n",
      "['id_185', 38.493935279714314]\n",
      "['id_186', 27.038919092643795]\n",
      "['id_187', 65.58170967424584]\n",
      "['id_188', 7.037306380769554]\n",
      "['id_189', 52.714477134115675]\n",
      "['id_190', 38.20645933704975]\n",
      "['id_191', 21.1698010595578]\n",
      "['id_192', 30.247556879488396]\n",
      "['id_193', 2.714422989716301]\n",
      "['id_194', 19.932932587640845]\n",
      "['id_195', -3.4133323376039164]\n",
      "['id_196', 32.44599940281314]\n",
      "['id_197', 10.58297302997993]\n",
      "['id_198', 21.775225707258436]\n",
      "['id_199', 62.465292065677886]\n",
      "['id_200', 24.132943687316477]\n",
      "['id_201', 26.20123964740091]\n",
      "['id_202', 63.74447723440287]\n",
      "['id_203', 2.8342977741290394]\n",
      "['id_204', 14.379246986978838]\n",
      "['id_205', 9.369850731753887]\n",
      "['id_206', 9.881166613595397]\n",
      "['id_207', 3.494945358972135]\n",
      "['id_208', 122.6080493792178]\n",
      "['id_209', 21.083513014480573]\n",
      "['id_210', 17.532220599455094]\n",
      "['id_211', 20.183098344597024]\n",
      "['id_212', 36.39313221228185]\n",
      "['id_213', 34.93515120529068]\n",
      "['id_214', 18.830312661458635]\n",
      "['id_215', 38.344555522723326]\n",
      "['id_216', 77.91663413807036]\n",
      "['id_217', 1.7953235508882106]\n",
      "['id_218', 13.445827939135764]\n",
      "['id_219', 36.131155590412135]\n",
      "['id_220', 15.150403498166295]\n",
      "['id_221', 12.941848334417914]\n",
      "['id_222', 113.12524093786391]\n",
      "['id_223', 15.224604677934375]\n",
      "['id_224', 14.824025968612048]\n",
      "['id_225', 59.267353688540446]\n",
      "['id_226', 10.583695290718483]\n",
      "['id_227', 20.99306256353216]\n",
      "['id_228', 9.789365880830365]\n",
      "['id_229', 4.7711800087059215]\n",
      "['id_230', 47.92780690481288]\n",
      "['id_231', 12.399438394751042]\n",
      "['id_232', 48.14647656264415]\n",
      "['id_233', 40.46638039656412]\n",
      "['id_234', 16.940590270332923]\n",
      "['id_235', 41.266544489418685]\n",
      "['id_236', 69.027892033729]\n",
      "['id_237', 40.346249244122426]\n",
      "['id_238', 14.313743982871063]\n",
      "['id_239', 15.770726634219757]\n",
      "Prediction results saved to answer.csv\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import csv\n",
    "\n",
    "# ==================== 数据预处理 ====================\n",
    "# 读取训练数据\n",
    "data = pd.read_csv('train.csv', encoding='big5')\n",
    "\n",
    "# 数据预处理\n",
    "data = data.iloc[:, 3:]  # 删除前三列表头列\n",
    "data[data == 'NR'] = 0  # 将NR替换为0\n",
    "raw_data = data.to_numpy()  # 转换为numpy数组 (4320, 24)\n",
    "\n",
    "# 将数据按月重组 (12个月×18个特征×480小时)\n",
    "month_data = {}\n",
    "for month in range(12):\n",
    "    sample = np.empty([18, 480])\n",
    "    for day in range(20):\n",
    "        sample[:, day * 24 : (day + 1) * 24] = raw_data[18 * (20 * month + day) : 18 * (20 * month + day + 1), :]\n",
    "    month_data[month] = sample\n",
    "\n",
    "# 提取特征和标签 (每9小时作为输入，第10小时的PM2.5作为输出)\n",
    "x = np.empty([12 * 471, 18 * 9], dtype=float)  # 特征矩阵 (5652×162)\n",
    "y = np.empty([12 * 471, 1], dtype=float)       # 标签矩阵 (5652×1)\n",
    "\n",
    "for month in range(12):\n",
    "    for day in range(20):\n",
    "        for hour in range(24):\n",
    "            if day == 19 and hour > 14:  # 防止越界\n",
    "                continue\n",
    "            # 提取9小时的特征数据\n",
    "            x[month * 471 + day * 24 + hour, :] = month_data[month][:, day * 24 + hour : day * 24 + hour + 9].reshape(1, -1)\n",
    "            # 提取第10小时的PM2.5值\n",
    "            y[month * 471 + day * 24 + hour, 0] = month_data[month][9, day * 24 + hour + 9]\n",
    "\n",
    "# 数据标准化\n",
    "mean_x = np.mean(x, axis=0)\n",
    "std_x = np.std(x, axis=0)\n",
    "for i in range(len(x)):\n",
    "    for j in range(len(x[0])):\n",
    "        if std_x[j] != 0:\n",
    "            x[i][j] = (x[i][j] - mean_x[j]) / std_x[j]\n",
    "\n",
    "# ==================== 模型训练 ====================\n",
    "dim = 18 * 9 + 1  # 特征维度+偏置项\n",
    "w = np.zeros([dim, 1])\n",
    "x = np.concatenate((np.ones([12 * 471, 1]), x), axis=1).astype(float)  # 添加偏置项\n",
    "\n",
    "# 训练参数\n",
    "learning_rate = 100\n",
    "iter_time = 1000\n",
    "adagrad = np.zeros([dim, 1])\n",
    "eps = 1e-10\n",
    "\n",
    "# Adagrad梯度下降\n",
    "for t in range(iter_time):\n",
    "    loss = np.sqrt(np.sum(np.power(np.dot(x, w) - y, 2)) / (471 * 12))  # RMSE\n",
    "    if t % 100 == 0:\n",
    "        print(f'Iteration: {t}, Loss: {loss}')\n",
    "    \n",
    "    gradient = 2 * np.dot(x.transpose(), np.dot(x, w) - y)  # 计算梯度\n",
    "    adagrad += gradient ** 2  # 累积梯度平方\n",
    "    w -= learning_rate * gradient / np.sqrt(adagrad + eps)  # 更新参数\n",
    "\n",
    "np.save('weight.npy', w)\n",
    "print('Training completed.')\n",
    "\n",
    "# ==================== 测试预测 ====================\n",
    "# # 读取测试数据\n",
    "# testdata = pd.read_csv('test.csv', header=None)\n",
    "# test_data = testdata.iloc[:, 2:]  # 去除前两列\n",
    "# test_data[test_data == 'NR'] = 0\n",
    "# test_data = test_data.to_numpy()\n",
    "\n",
    "# # 测试数据处理（修正后版本）\n",
    "# testdata = pd.read_csv('test.csv', header=None)\n",
    "# test_data = testdata.iloc[:, 2:].copy()  # 显式创建副本\n",
    "# test_data[test_data == 'NR'] = 0  # 现在安全了\n",
    "# test_data = test_data.to_numpy()\n",
    "\n",
    "# 或者更简洁的写法：\n",
    "test_data = pd.read_csv('test.csv', header=None).iloc[:, 2:].replace('NR', 0).to_numpy()\n",
    "\n",
    "\n",
    "# 准备测试数据\n",
    "test_x = np.empty([240, 18 * 9])\n",
    "for i in range(240):\n",
    "    test_x[i, :] = test_data[i * 18 : (i + 1) * 18, :].reshape(1, -1)\n",
    "\n",
    "# 标准化测试数据\n",
    "for i in range(len(test_x)):\n",
    "    for j in range(len(test_x[0])):\n",
    "        if std_x[j] != 0:\n",
    "            test_x[i, j] = (test_x[i, j] - mean_x[j]) / std_x[j]\n",
    "\n",
    "test_x = np.concatenate((np.ones([240, 1]), test_x), axis=1).astype(float)\n",
    "\n",
    "# 预测并保存结果\n",
    "w = np.load('weight.npy')\n",
    "ans_y = np.dot(test_x, w)\n",
    "\n",
    "with open('answer.csv', mode='w', newline='') as answer_file:\n",
    "    csv_writer = csv.writer(answer_file)\n",
    "    csv_writer.writerow(['id', 'value'])\n",
    "    for i in range(240):\n",
    "        row = ['id_' + str(i), ans_y[i][0]]\n",
    "        csv_writer.writerow(row)\n",
    "        print(row)\n",
    "\n",
    "print('Prediction results saved to answer.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "368e1b50-7e31-4441-bbdc-3d3d4033b744",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.21"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
